.. _xslt:

XSLT WFS output format module
=============================

The ``xslt`` module for GeoServer is a WFS output format generator which brings together a base output,
such as GML, and a XSLT 1.0 style sheet to generate a new textual output format of user choosing.

The configuration for this output format can be either performed directly on disk, or via a REST API.

Manual configuration
--------------------

All the configuration for the output resides in the ``$GEOSERVER_DATA_DIR/wfs/transform`` folder,
which is going to be created on startup when missing if the XSLT output format has been installed
in GeoServer.

Each XSLT transformation must be configured with its own xml file in the ``$GEOSERVER_DATA_DIR/wfs/transform`` folder,
which in turn points to a xslt file for the transformation. While the names can be freeform, it is suggested to follow
a simple naming convention:

*  <mytransformation>.xml for the xml config file
*  <mytransformation>.xslt for the xslt tile

Transformations can be either global, and thus applicable to any feature type, or type specific, in which case
the transformation knows about the specific attributes of the transformed feature type.

Global transformation example
-----------------------------

Here is an example of a global transformation setup. The ``$GEOSERVER_DATA_DIR/wfs/transform/global.xml`` file will
look like:

.. code-block:: xml

  <transform>
    <sourceFormat>text/xml; subtype=gml/2.1.2</sourceFormat>
    <outputFormat>HTML</outputFormat>
    <outputMimeType>text/html</outputMimeType>
    <fileExtension>html</fileExtension>
    <xslt>global.xslt</xslt>
  </transform>

Here is an explanation of each element:

*  ``sourceFormat`` (mandatory): the output format used as the source of the XSLT transformation
*  ``outputFormat`` (mandatory): the output format generated by the transformation
*  ``outputMimeType`` (optional): the mime type for the generated output. In case it's missing, the ``outputFormat`` is assumed to be a mime type and used for the purpose.
*  ``fileExtension`` (optional): the file extension for the generated output. In case it's missing ``txt`` will be used.
*  ``xslt`` (mandatory): the name of XSLT 1.0 style sheet used for the transformation

The associated XSLT file will be ``$GEOSERVER_DATA_DIR/wfs/transform/global.xslt`` folder, and it will be able to transform any GML2 input into a corresponding HTML file.
Here is an example:

.. code-block:: xml

  <?xml version="1.0" encoding="ISO-8859-1"?>
  <xsl:stylesheet version="1.0" xmlns:wfs="http://www.opengis.net/wfs"
    xmlns:tiger="http://www.census.gov" xmlns:gml="http://www.opengis.net/gml"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
      <html>
        <body>
        <xsl:for-each select="wfs:FeatureCollection/gml:featureMember/*">
          <h2><xsl:value-of select="@fid"/></h2>
          <table border="1">
            <tr>
              <th>Attribute</th>
              <th>Value</th>
            </tr>
              <!-- [not(*)] strips away all nodes having 
                   children, in particular, geometries -->
              <xsl:for-each select="./*[not(*)]">
              <tr>
                <td>
                  <xsl:value-of select="name()" />
                </td>
                <td>
                  <xsl:value-of select="." />
                </td>
              </tr>
              </xsl:for-each>
          </table>
       </xsl:for-each>
       </body>
     </html>
    </xsl:template>
  </xsl:stylesheet>

Type specific transformations
-----------------------------

Type specific transformations can refer to a specific type and leverage its attributes directly. While not required, it is good practice
to setup a global transformation that can handle any feature type (since the output format is declared in the capabilities document as being
general, not type specific) and then override it for specific feature types in order to create special transformations for them.

Here is an example of a transformation declaration that is type specific, that will be located at ``$GEOSERVER_DATA_DIR/wfs/transform/html_bridges.xml``

.. code-block:: xml

  <transform>
    <sourceFormat>text/xml; subtype=gml/2.1.2</sourceFormat>
    <outputFormat>HTML</outputFormat>
    <outputMimeType>text/html</outputMimeType>
    <fileExtension>html</fileExtension>
    <xslt>html_bridges.xslt</xslt>
    <featureType>
      <id>cite:Bridges</id>
    </featureType>
  </transform>

The extra ``featureType`` element associates the transformation to the specific feature type

The associated xslt file will be located at ``$GEOSERVER_DATA_DIR/wfs/transform/html_bridges.xslt`` and will 
leveraging knowledge about the input attributes:

.. code-block:: xml

  <?xml version="1.0" encoding="ISO-8859-1"?>
  <xsl:stylesheet version="1.0" xmlns:wfs="http://www.opengis.net/wfs"
    xmlns:cite="http://www.opengis.net/cite" xmlns:gml="http://www.opengis.net/gml"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
      <html>
        <body>
          <h2>Bridges</h2>
          <xsl:for-each
              select="wfs:FeatureCollection/gml:featureMember/cite:Bridges">
          <ul>
            <li>ID: <xsl:value-of select="@fid" /></li>
            <li>FID: <xsl:value-of select="cite:FID" /></li>
            <li>Name: <xsl:value-of select="cite:NAME" /></li>
          </ul>
          <p/>
          </xsl:for-each>
        </body>
      </html>
    </xsl:template>
  </xsl:stylesheet>

.. note:: While writing the XSLT always remember to declare all prefixes used in the sheet in the ``stylesheet`` element, otherwise you might encounter hard to understand error messages

A specific feature type can be associated to multiple output formats. While uncommon, the same xslt file can also be associated to multiple feature types by creating 
multiple xml configuration files, and associating a different feature type in each.

Rest configuration
------------------

Transformations can be created, updated and deleted via the REST api (normally, this requires administrator privileges). 
Each transformation is represented with the same XML format used on disk, but with two variants:

* a new ``name`` attribute appears, which matches the XML file name
* the ``featureType`` element contains also a link to the resource representing the feature type in the REST config tree

For example:

.. code-block:: xml

  <transform>
    <name>test</name>
    <sourceFormat>text/xml; subtype=gml/2.1.2</sourceFormat>
    <outputFormat>text/html</outputFormat>
    <fileExtension>html</fileExtension>
    <xslt>test-tx.xslt</xslt>
    <featureType>
      <name>tiger:poi</name>
      <atom:link xmlns:atom="http://www.w3.org/2005/Atom" rel="alternate" href="http://localhost:8080/geoserver/rest/workspaces/cite/datastores/cite/featuretypes/bridges.xml" type="application/xml"/>
    </featureType>
  </transform>

Here is a list of resources and the HTTP methods that can be used on them.

``/rest/services/wfs/transforms[.<format>]``

.. list-table::
   :header-rows: 1

   * - Method
     - Action
     - Return Code
     - Formats
     - Default Format
     - Parameters
   * - GET
     - List all available transforms
     - 200
     - HTML, XML, JSON
     - HTML
     -
   * - POST
     - Add a new transformation
     - 201, with ``Location`` header
     - XML, JSON
     -
     - name, sourceFormat, outputFormat, outputMimeType
   * - PUT
     - Update global settings
     - 200
     - XML, JSON
     -
     -
   * - DELETE
     -
     - 405
     -
     -
     -

The ``POST`` method can be used to create a transformation in two ways:

*  if the content type used is ``application/xml`` the server will assume a ``<transform>`` definition is being posted,
   and the XSLT will have to be uploaded separately using a ``PUT`` request with content type ``application/xslt+xml``
   against the transformation resource
*  if the content type used is ``application/xslt+xml`` the server will assume the XSLT itself is being posted, and
   the ``name``, ``sourceFormat``, ``outputFormat``, ``outputMimeType`` query parameters will be used to fill in the
   transform configuration instead

``/rest/services/wfs/transforms/<transform>[.<format>]``

.. list-table::
   :header-rows: 1

   * - Method
     - Action
     - Return Code
     - Formats
     - Default Format
   * - GET
     - Returns the transformation
     - 200
     - HTML, XML, XSLT
     - HTML
   * - POST
     - 
     - 405
     - 
     -
   * - PUT
     - Updates either the transformation configuration, or its XSLT, depending on the mime type used
     - 200
     - XML, XSLT
     - 
   * - DELETE
     - Deletes the transformation
     - 200
     -
     -

The PUT operation behaves differently depending on the content type used in the request:

*  if the content type used is ``application/xml`` the server will assume a ``<transform>`` definition is being sent
   and will update it
*  if the content type used is ``application/xslt+xml`` the server will assume the XSLT itself is being posted, as such
   the configuration won't be modified, but the XSLT associated to it will be overwritten instead


